using UserMgr.Domain.Entities;
using UserMgr.Domain.ValueObjects;

namespace UserMgr.Domain;

public class UserDomainService
{

    private IUserRepository userRepository;
    private ISmsCodeSender smsCodeSender;
    
    public UserDomainService(IUserRepository userRepository, ISmsCodeSender smsCodeSender)
    {
        this.userRepository = userRepository;
        this.smsCodeSender = smsCodeSender;
    }

    public void ResetAccessFail(User user)
    {
        user.UserAccessFail.Reset();
    }

    public bool IsLockOut(User user)
    {
        return user.UserAccessFail.IsLockOut();
    }

    public void AccessFail(User user)
    {
        user.UserAccessFail.Fail();
    }

    public async Task<UserAccessResult> CheckLoginAsync(PhoneNumber phoneNumber, string password)
    {
        User? user = await userRepository.FindOneAsync(phoneNumber);
        
        UserAccessResult result;
        if (user==null)
            result = UserAccessResult.PhoneNUmberNotFound;
        else if (user.HasPassWord()==false)
            result = UserAccessResult.NoPassword;
        else if (user.CheckPassword(password))
            result = UserAccessResult.Ok;
        else
            result = UserAccessResult.PasswordError;

        if (user!=null)
        {
            if (result == UserAccessResult.Ok)
                this.ResetAccessFail(user);
            else
                this.ResetAccessFail(user);
        }

        UserAccessResultEvent @event = new(phoneNumber, result);
        await userRepository.PublishEventAsync(@event);
        return result;
    }

    public async Task<CheckCodeResult> CheckCodeAsync(PhoneNumber phoneNumber, string code)
    {
        User? user = await userRepository.FindOneAsync(phoneNumber);
        
        if (user==null)
            return CheckCodeResult.PHoneNumberNotFound;
        if (IsLockOut(user))
            return CheckCodeResult.Lockout;

        string? codeInServer = await userRepository.RetrievePhoneCodeAsync(phoneNumber);
        
        if (string.IsNullOrEmpty(codeInServer))
            return CheckCodeResult.CodeError;
        if (code==codeInServer)
            return CheckCodeResult.Ok;
        
        AccessFail(user);
        return CheckCodeResult.CodeError;
    }
}